package com.viknix.threadpool.manager.client.core;

import com.alibaba.fastjson.JSON;
import com.viknix.threadpool.manager.client.alertor.ThreadPoolAlertor;
import com.viknix.threadpool.manager.client.exception.TpmProcessException;
import com.viknix.threadpool.manager.client.factory.RejectedHandlerFactory;
import com.viknix.threadpool.manager.client.global.GlobalThreadPoolManage;
import com.viknix.threadpool.manager.client.http.HttpAgent;
import com.viknix.threadpool.manager.common.model.PoolParameterInfo;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.*;

import static com.viknix.threadpool.manager.common.constant.Constants.CONFIG_CONTROLLER_PATH;
import static com.viknix.threadpool.manager.common.constant.Constants.ENCODE;

/**
 * @Author: Dongqi
 * @Date: 2021/10/24 15:02
 * @Version 1.0
 * @Description 动态刷新器
 */
@Slf4j
@AllArgsConstructor
public class ThreadPoolDynamicRefresh {

    /**
     * 解析并刷新动态线程池参数，发送配置变更通知
     *
     * @param content 服务端新的配置信息
     */
    public static void refreshDynamicPool(String content, HttpAgent httpAgent) {

        PoolParameterInfo newParameter = null;
        PoolParameterInfo oldParameter = null;
        try {
            newParameter = JSON.parseObject(content, PoolParameterInfo.class);
            // 获取旧的配置
            oldParameter = GlobalThreadPoolManage.getPoolParameter(newParameter.getThreadPoolId());
            if (oldParameter == null) {
                throw new TpmProcessException("全局管理器中未登记该线程池配置！");
            }
            // 刷新动态线程池参数
            refreshDynamicPool(newParameter, oldParameter);
        } catch (Exception e) {
            e.printStackTrace();
            log.warn(">>> 开始回滚服务端操作！");
            List<String> params = new ArrayList<String>();
            params.add(content);
            params.add(JSON.toJSONString(oldParameter));
            try {
                httpAgent.httpPost(CONFIG_CONTROLLER_PATH, null, params, ENCODE, 3000L);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            // 因为刷新动作不是由长轮询线程执行的，所以即使这里抛出异常，不会影响长轮询线程的执行，当前刷新任务会被取消
            throw new TpmProcessException("线程池参数动态刷新异常！");
        }
        // 委托消息发生器发送配置变更通知
        ThreadPoolAlertor.sendPoolConfigChange(newParameter, oldParameter);
    }

    /**
     * 刷新动态线程池参数
     *
     * @param newParameter 新的线程池配置
     * @param oldParameter 旧的线程池配置
     */
    public static void refreshDynamicPool(PoolParameterInfo newParameter, PoolParameterInfo oldParameter) {

        String threadPoolId = newParameter.getThreadPoolId();
        // 从全局管理器中获取该线程池
        ThreadPoolExecutor executor = GlobalThreadPoolManage.getExecutorService(threadPoolId).getThreadPool();
        // 获取原来的配置信息
        int oldCorePoolSize = oldParameter.getCorePoolSize();
        int oldMaximumPoolSize = executor.getMaximumPoolSize();
        int oldCapacity = oldParameter.getCapacity();
        long oldKeepAliveTime = oldParameter.getKeepAliveTime();
        int oldQueryType = oldParameter.getQueueType();
        int oldRejectedType = oldParameter.getRejectedType();
        boolean oldAlert = oldParameter.alert();
        Integer oldCapacityAlert = Optional.ofNullable(oldParameter.getCapacityAlert()).orElse(0);
        Integer oldLivenessAlert = Optional.ofNullable(oldParameter.getLivenessAlert()).orElse(0);
        // 刷新动态线程池参数
        changePoolInfo(executor, newParameter);
        // 向全局管理其中注册新的线程池参数
        GlobalThreadPoolManage.registerPoolParameter(threadPoolId, newParameter);

        log.info(">>> [😊 Thread pool refresh] threadPoolId :: [{}] coreSize :: [{}], maxSize :: [{}], queueType :: [{}], capacity :: [{}], keepAliveTime :: [{}], rejectedType :: [{}], " +
                        "isAlert :: [{}], capacityAlert :: [{}], livenessAlert :: [{}]",
                threadPoolId.toUpperCase(),
                String.format("%s=>%s", oldCorePoolSize, newParameter.getCorePoolSize()),
                String.format("%s=>%s", oldMaximumPoolSize, newParameter.getMaxPoolSize()),
                String.format("%s=>%s", oldQueryType, newParameter.getQueueType()),
                String.format("%s=>%s", oldCapacity, newParameter.getCapacity()),
                String.format("%s=>%s", oldKeepAliveTime, newParameter.getKeepAliveTime()),
                String.format("%s=>%s", oldRejectedType, newParameter.getRejectedType()),
                String.format("%s=>%s", oldAlert, newParameter.alert()),
                String.format("%s=>%s", oldCapacityAlert, Optional.ofNullable(newParameter.getCapacityAlert()).orElse(0)),
                String.format("%s=>%s", oldLivenessAlert, Optional.ofNullable(newParameter.getLivenessAlert()).orElse(0)));
    }

    /**
     * 动态刷新线程池参数
     *
     * @param executor  被刷新的线程池对象
     * @param parameter 新的参数
     */
    public static void changePoolInfo(ThreadPoolExecutor executor, PoolParameterInfo parameter) {

        DynamicThreadPoolExecutor dynamicExecutor = (DynamicThreadPoolExecutor) executor;
        // 更新拒绝策略
        Optional.ofNullable(parameter.getRejectedType()).ifPresent(rejectedType -> {
            RejectedExecutionHandler policy = RejectedHandlerFactory.createPolicy(parameter.getRejectedType());
            dynamicExecutor.setRejectedExecutionHandler(policy);
        });
        Optional.ofNullable(parameter.getCorePoolSize()).ifPresent(corePoolSize -> dynamicExecutor.setCorePoolSize(parameter.getCorePoolSize()));
        Optional.ofNullable(parameter.getMaxPoolSize()).ifPresent(maxPoolSize -> dynamicExecutor.setMaximumPoolSize(parameter.getMaxPoolSize()));
        Optional.ofNullable(parameter.getKeepAliveTime()).ifPresent(keepAliveTime -> dynamicExecutor.setKeepAliveTime(parameter.getKeepAliveTime(), TimeUnit.SECONDS));
        Optional.ofNullable(parameter.getIsAlert()).ifPresent(isAlert -> dynamicExecutor.getAlertorParam().setAlert(parameter.alert()));
        Optional.ofNullable(parameter.getCapacityAlert()).ifPresent(capacityAlert -> dynamicExecutor.getAlertorParam().setCapacityAlarm(capacityAlert));
        Optional.ofNullable(parameter.getLivenessAlert()).ifPresent(livenessAlert -> dynamicExecutor.getAlertorParam().setLivenessAlarm(livenessAlert));
        // TODO 阻塞队列的容量动态刷新
    }

}
